package service

import (
	"ia/apps/admin/web/dts/sin"
	"ia/apps/admin/web/dts/sout"
	"ia/common/model/modeladmin"
	"ia/common/storage"
	"ia/common/support"
	"ia/common/support/define"

	"github.com/kataras/golog"
	"github.com/kataras/iris/v12"
	"gorm.io/gorm"
)

type AdminMenuService interface {
	Create(ctx iris.Context)
	Delete(ctx iris.Context)
	Update(ctx iris.Context)
	List(ctx iris.Context)
}

func NewAdminMenuService() *adminMenuService {
	return &adminMenuService{}
}

type adminMenuService struct{}

func (impl *adminMenuService) Create(ctx iris.Context) {
	var (
		code define.Code
		err  error
		in   sin.AdminMenuIn
	)
	if err = ctx.ReadJSON(&in); err != nil {
		goto ERR
	}
	if err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		if err = tx.Create(&in).Error; err != nil {
			return err
		}
		if len(in.BidList) > 0 {
			menuButtons := make([]modeladmin.AdminMenuButton, 0)
			for _, v := range in.BidList {
				menuButtons = append(menuButtons, modeladmin.AdminMenuButton{
					Mid: in.Id,
					Bid: uint(v),
				})
			}
			if err = tx.CreateInBatches(menuButtons, 100).Error; err != nil {
				return err
			}
		}
		return nil
	}); err != nil {
		goto ERR
	}
	if err = storage.GDB1.Create(&in).Error; err != nil {
		goto ERR
	}
	support.Ok_(ctx)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminMenuService) Delete(ctx iris.Context) {
	var (
		code       define.Code
		err        error
		idList     = make([]int, 0)
		metaIdList = make([]int, 0)
	)
	if err = ctx.ReadJSON(&idList); err != nil {
		goto ERR
	}

	if err = storage.GDB1.Model(&modeladmin.AdminMenu{}).Select("meta_id").
		Where("id in ? or parent_id in ?", idList, idList).Scan(&metaIdList).Error; err != nil {
		goto ERR
	}

	if len(metaIdList) > 0 {
		if err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
			if err = tx.Delete(&modeladmin.AdminMenu{}, "id in ? or parent_id in ?", idList, idList).Error; err != nil {
				return err
			}
			if err = tx.Delete(&modeladmin.AdminMenuMeta{}, "id in ?", metaIdList).Error; err != nil {
				return err
			}
			if err = tx.Delete(&modeladmin.AdminRoleMenu{}, "mid in ?", idList).Error; err != nil {
				return err
			}
			if err = tx.Delete(&modeladmin.AdminMenuButton{}, "mid in ?", idList).Error; err != nil {
				return err
			}
			return nil
		}); err != nil {
			goto ERR
		}
	}
	support.Ok_(ctx)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminMenuService) Update(ctx iris.Context) {
	var (
		code define.Code
		err  error
		in   sin.AdminMenuIn
	)
	if err = ctx.ReadJSON(&in); err != nil {
		goto ERR
	}

	if err = storage.GDB1.Transaction(func(tx *gorm.DB) error {
		if err = tx.Save(&in).Error; err != nil {
			return err
		}
		if err = tx.Save(&in.Meta).Error; err != nil {
			return err
		}
		if err = tx.Delete(&modeladmin.AdminMenuButton{}, "mid=?", in.Id).Error; err != nil {
			return err
		}
		if len(in.BidList) > 0 {
			menuButtons := make([]modeladmin.AdminMenuButton, 0)
			for _, v := range in.BidList {
				menuButtons = append(menuButtons, modeladmin.AdminMenuButton{
					Mid: in.Id,
					Bid: uint(v),
				})
			}
			if err = tx.CreateInBatches(menuButtons, 100).Error; err != nil {
				return err
			}
		}
		return nil
	}); err != nil {
		goto ERR
	}
	support.Ok_(ctx)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminMenuService) List(ctx iris.Context) {
	var (
		code   define.Code
		err    error
		rid    = ctx.URLParamInt64Default("rid", 0)
		result = make([]*sout.AdminMenuOut, 0)
	)

	if err = storage.GDB1.Preload("Meta").Preload("Children.Meta").
		Order("sort").
		Find(&result, "parent_id=0").Error; err != nil {
		goto ERR
	}

	if err = impl.deep(result, rid); err != nil {
		goto ERR
	}
	support.Ok(ctx, result)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminMenuService) OwnList(ctx iris.Context) {
	var (
		code    define.Code
		err     error
		uid     = ctx.Values().GetInt64Default(define.Uid, 0)
		ridList = make([]int, 0) // 用户对应的角色列表
		pidList = make([]int, 0) // 用户-角色拥有的，所有的父菜单ID
		cidList = make([]int, 0) // 用户-角色拥有的，所有的子菜单ID
		result  = make([]*sout.AdminMenuOut, 0)
		db      = storage.GDB1.Preload("Meta").Preload("Children.Meta")
	)
	if uid == 1 {
		if err = db.Find(&result, "parent_id=0").Error; err != nil {
			goto ERR
		}
		// if err = storage.GDB1.Model(&modeladmin.AdminMenu{}).
		// 	Select("id").Where("parent_id<>0").Scan(&cidList).Error; err != nil {
		// 	goto ERR
		// }
	} else {
		if err = storage.GDB1.Raw(`
		select distinct parent_id as mid from admin_menu where id in (
		SELECT distinct mid FROM admin_role_menu WHERE rid in (
		SELECT v1 FROM casbin_rule WHERE ptype='g' AND v0=?
		))`, uid).Select("mid").Scan(&pidList).Error; err != nil {
			goto ERR
		}
		if err = db.Find(&result, "parent_id=0 AND id in ?", pidList).Error; err != nil {
			goto ERR
		}

		if err = storage.GDB1.Raw(`
		select distinct id as mid from admin_menu where id in (
		SELECT distinct mid FROM admin_role_menu WHERE rid in (
		SELECT v1 FROM casbin_rule WHERE ptype='g' AND v0=?
		)) AND parent_id<>0`, uid).Select("mid").Scan(&cidList).Error; err != nil {
			goto ERR
		}
	}

	if err = storage.GDB1.Raw("SELECT v1 FROM casbin_rule WHERE ptype='g' AND v0=?", uid).Scan(&ridList).Error; err != nil {
		goto ERR
	}
	if err = impl.deepOwn(result, uid, cidList); err != nil {
		goto ERR
	}
	support.Ok(ctx, result)
	return
ERR:
	golog.Errorf("错误：%s", err)
	support.InternalServerError(ctx, code)
}

func (impl *adminMenuService) deep(parent []*sout.AdminMenuOut, rid int64) error {
	if len(parent) > 0 {
		for _, v1 := range parent {
			// 菜单的所有按钮
			if err := storage.GDB1.Raw(`
			SELECT * FROM admin_button WHERE id in (
			SELECT bid FROM admin_menu_button WHERE mid=?
			) AND enable > 0
			`, v1.Id).Scan(&v1.ButtonList).Error; err != nil {
				return err
			}
			// 获取 角色-菜单 所拥有的按钮集合
			if rid > 0 {
				if err := storage.GDB1.Raw("SELECT bid FROM admin_role_menu WHERE rid=? AND mid=?", rid, v1.Id).
					Scan(&v1.OwnedBidList).Error; err != nil {
					return err
				}
			}

			if len(v1.Children) > 0 {
				if err := storage.GDB1.Preload("Meta").Preload("Children.Meta").
					Order("sort").
					Find(&v1.Children, "parent_id=?", v1.Id).Error; err != nil {
					return err
				}
				if err := impl.deep(v1.Children, rid); err != nil {
					return err
				}
			}
		}
	}
	return nil
}

// uid 用户ID
// cidList 所有的子菜单结合
func (impl *adminMenuService) deepOwn(parent []*sout.AdminMenuOut, uid int64, cidList []int) error {
	if len(parent) > 0 {
		for _, v1 := range parent {
			// 角色拥有的按钮
			if uid > 1 {
				if err := storage.GDB1.Raw(`
				SELECT * FROM admin_button WHERE id in (
				SELECT distinct bid FROM admin_role_menu WHERE mid=?) AND enable > 0`, v1.Id).
					Scan(&v1.ButtonList).Error; err != nil {
					return err
				}
			} else {
				if err := storage.GDB1.Raw(`
				SELECT * FROM admin_button WHERE id in (
				SELECT bid FROM admin_menu_button WHERE mid=?
				) AND enable > 0`, v1.Id).Scan(&v1.ButtonList).Error; err != nil {
					return err
				}
			}

			if len(v1.Children) > 0 {
				db := storage.GDB1.Model(&sout.AdminMenuOut{}).Preload("Meta").Preload("Children.Meta").Order("sort")
				if len(cidList) > 0 {
					db.Where("id in ?", cidList)
				}
				if err := db.Find(&v1.Children, "parent_id=?", v1.Id).Error; err != nil {
					return err
				}
				// if err := storage.GDB1.Preload("Meta").Preload("Children.Meta").
				// 	Order("sort").
				// 	Find(&v1.Children, "parent_id=? AND id in ?", v1.Id, cidList).Error; err != nil {
				// 	return err
				// }
				if err := impl.deepOwn(v1.Children, uid, cidList); err != nil {
					return err
				}
			}
		}
	}
	return nil
}
